home *** CD-ROM | disk | FTP | other *** search
- /* Supporting c code for the EtermView class.
-
- For legal stuff see the file COPYRIGHT. */
-
- #include <libc.h>
- #include <appkit/nextstd.h>
- #include <errno.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <signal.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ioctl.h>
- #include <sys/wait.h>
- #include <sys/socket.h>
-
- #include "defaults.h"
- #include "etermSupport.h"
-
- /* Some random lab's phone number. Ask Tom Lord. */
- #define FIB20 6765
-
- extern int errno;
-
- /* Given the current environment, give us a new environment suitable for an
- emacs process with an event server on port 'eventportno' */
- char **
- patch_env (char **currentEnv, int eventportno)
- {
- static char term[] = "TERM=eterm";
- static char termcap[] = "TERMCAP=69|eterm|Terminal emulator for Gnu-emacs:co#80:li#24:cm=^u%d^u%d.:IC=^u%d_:DC=^u%d^d:AL=^u%d^o:DL=^u%d^k:bc=^b:bl=^g:cd=^[k:ce=^k:ch=^u%d.:cl=^[c:cr=^a:do=^n:im=^i:ei=^i:le=^b:mi:ms:nd=^f:nl=^j:se=^s:so=^s:up=^p:am:km:";
- char *eventhost;
- static char eventport[80];
- char **newEnv;
- int envSize, x, y;
- char hostname[1024];
-
- if (gethostname (hostname, sizeof (hostname)) == -1)
- {
- NXLogError ("gethostname: %s", strerror (errno));
- exit (1);
- }
-
- eventhost = malloc (strlen (hostname) + 12);
- strcpy (eventhost, "EVENT_HOST=");
- strcat (eventhost, hostname);
-
- sprintf (eventport, "EVENT_PORT=%d", eventportno);
-
- for (envSize = 0; currentEnv[envSize] != NULL; envSize++);
- newEnv = (char **) malloc (sizeof (char *) *(envSize + 5));
- for (x = y = 0; x < envSize; x++)
- if (strncmp (currentEnv[x], "TERM=", 5)
- && strncmp (currentEnv[x], "TERMCAP=", 8)
- && strncmp (currentEnv[x], "EVENT_HOST=", 11)
- && strncmp (currentEnv[x], "EVENT_PORT=", 11))
- newEnv[y++] = currentEnv[x];
- newEnv[y++] = term;
- newEnv[y++] = termcap;
- newEnv[y++] = eventhost;
- newEnv[y++] = eventport;
- newEnv[y] = NULL;
- return newEnv;
- } /* patch_env */
-
- /* Create the event server socket for an emacs process. Store the port
- number in the int ponted to by eventportno. */
- int
- create_server_socket (int *eventportno)
- {
- int EventServerSocket;
- struct sockaddr_in name;
- int portno = FIB20;
-
- if ((EventServerSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
- {
- NXLogError ("socket: %s", strerror (errno));
- exit (1);
- }
-
- while (portno < FIB20 + 100)
- {
- name.sin_family = AF_INET;
- name.sin_port = htons (portno);
- name.sin_addr.s_addr = INADDR_ANY;
-
- if (bind (EventServerSocket, (struct sockaddr *) &name, sizeof (name))
- == -1)
- {
- portno++;
- continue;
- }
- if (listen (EventServerSocket, 1) == -1)
- {
- NXLogError ("listen: %s", strerror (errno));
- exit (1);
- }
- *eventportno = portno;
- return EventServerSocket;
- }
- NXLogError ("bind: %s", strerror (errno));
- exit (1);
- } /* create_server_socket */
-
- /* Accept a connection on an event server socket. */
- int
- accept_server_connection (int serversocket)
- {
- int s;
- struct sockaddr_in name;
- int namelen = sizeof (name);
-
- if ((s = accept (serversocket, (struct sockaddr *) &name, &namelen)) == -1)
- return -1;
- return s;
- } /* accept_server_connection */
-
- /* The create_channel code is stolen from h19. "it should be replaced". */
- char ptcname[] = "/dev/ptyXX";
- char ptyname[] = "/dev/ttyXX";
-
- /* Grab a pty/tty pair for running a child emacs process. */
- void
- create_channel (int *master, int *slave, int *ptynumber)
- {
- int MasterChannel, PtyNumber, ShellChannel = -1;
- int pid;
- char c;
-
- pid = getpid ();
- if (setpgrp (0, pid) < 0)
- NXLogError ("setpgrp: %s", strerror (errno));
-
- /* Remove the current controling terminal -- will create a new one. */
- {
- int fd;
- fd = open ("/dev/tty", 2);
- if (fd >= 0)
- {
- if (ioctl (fd, TIOCNOTTY, NULL) < 0)
- NXLogError ("ioctl (TIOCNOTTY): %s", strerror (errno));
- close (fd);
- }
- }
-
- /* Find pseudo-teletype for subchannel to shell. */
- for (c = 'p'; c <= 'r'; c++)
- {
- ptcname[strlen ("/dev/pty")] = c;
- ptcname[strlen ("/dev/ptyX")] = '0';
- for (PtyNumber = 0; PtyNumber < 16; PtyNumber++)
- {
- ptcname[strlen ("/dev/ptyX")] = "0123456789abcdef"[PtyNumber];
- MasterChannel = open (ptcname, 2);
- if (MasterChannel < 0)
- continue;
- ptyname[strlen ("/dev/tty")] = c;
- ptyname[strlen ("/dev/ttyX")] = "0123456789abcdef"[PtyNumber];
- ShellChannel = open (ptyname, 2);
- if (ShellChannel >= 0)
- goto gotpty;
- close (MasterChannel);
- }
- }
-
- gotpty:
- if (MasterChannel < 0 || ShellChannel < 0)
- {
- NXLogError ("Can't connect subchannel");
- exit (1);
- }
-
- /* Adjust terminal driver for Master Channel. */
- {
- int nonBlock = 1;
- /* Exclusive use of Master. */
- if (ioctl (MasterChannel, FIOCLEX, NULL) < 0)
- NXLogError ("ioctl (FIOCLEX): %s", strerror (errno));
- if (ioctl (MasterChannel, FIONBIO, &nonBlock) < 0)
- NXLogError ("ioctl (FIONBIO): %s", strerror (errno));
- }
-
- /* Adjust terminal driver for Shell Channel. */
- {
- int line_discipline = NTTYDISC;
- int local_mode;
- struct sgttyb ttystate;
-
- if (ioctl (ShellChannel, TIOCHPCL, NULL) < 0)
- perror ("TIOCHPCL");
- if (ioctl (ShellChannel, TIOCSETD, &line_discipline) < 0)
- perror ("TIOCSETD");
- if (ioctl (ShellChannel, TIOCGETP, &ttystate) < 0)
- perror ("TIOCGETP");
- ttystate.sg_flags = CRMOD | ANYP | ECHO;
-
- /* CRMOD - tread CR like LF; output of LF is CR/LF
- XTABS - change TABS to sequence of blanks
- ANYP - Any parity okay
- ECHO - echo characters (full duplex) */
- ttystate.sg_erase = '\010';
- if (ioctl (ShellChannel, TIOCSETP, &ttystate) < 0)
- perror ("TIOCSETP");
- if (ioctl (ShellChannel, TIOCLGET, &local_mode) < 0)
- perror ("TIOCLGET");
-
- /* LCRTBS - CRT back space to ^H
- LCRTERA - backspace-space-backspace
- LCRTKIL - erase as LCRTERA for line kill too
- LCTLECH - echo non-printing characters as ^X. */
- local_mode |= LCRTBS | LCRTKIL | LCRTERA | LCTLECH;
- if (ioctl (ShellChannel, TIOCLSET, &local_mode) < 0)
- perror ("TIOCLSET");
- }
- *master = MasterChannel;
- *slave = ShellChannel;
- *ptynumber = PtyNumber;
- } /* create_channel */
-
- /* Reap zombie processes. If any child processes stopped themselves, give
- them a kick in the pants. */
- static void
- ShellDone ()
- {
- int pid;
- union wait stat;
-
- while ((pid = wait3 (&stat, WUNTRACED | WNOHANG, 0 )) > 0)
- {
- if (WIFSTOPPED (stat))
- kill (pid,SIGCONT);
- }
- } /* ShellDone */
-
- /* Fork and exec the child emacs. */
- void
- fork_shell (char *name, char **args, char **env, int channel)
- {
- int pid;
-
- signal (SIGCLD, ShellDone);
- signal (SIGTTOU, SIG_IGN);
-
- if ((pid = fork ()) < 0)
- {
- NXLogError ("fork: %s", strerror (errno));
- exit (1);
- }
-
- if (pid == 0)
- {
- int i;
- int cpid;
-
- cpid = getpid ();
- if (ioctl (channel, TIOCSPGRP, &cpid) < 0)
- perror ("TIOCSPGRP");
- if (setpgrp (0, cpid) < 0)
- perror ("setpgrp");
-
- dup2 (channel, 0);
- dup2 (channel, 1);
- for (i = getdtablesize (); i > 2; i--)
- close (i);
-
- execve (name, args, env);
- NXLogError ("%s: %s", name, strerror (errno));
- execve (DEFAULT_EMACS_PATH, args, env);
- NXLogError ("%s: %s", DEFAULT_EMACS_PATH, strerror (errno));
- exit (1);
- }
- } /* fork_shell */
-